#include "enc_hw_intf.h"
#include "bsp/bsp_drivers.h"
#include "utils/logger.h"
#include "os/os.h"
#if CONFIG_USE_MAG_ENCODER
enc_spi_t enc_spi_;
static void enc_spi_cplt_handler(void *, bool success);

static SPI_InitTypeDef spi_config_ = {
	.Mode = SPI_MODE_MASTER,
	.Direction = SPI_DIRECTION_2LINES,
	.DataSize = SPI_DATASIZE_16BIT,
	.CLKPolarity = SPI_POLARITY_LOW,
	.CLKPhase = SPI_PHASE_2EDGE,
	.NSS = SPI_NSS_SOFT,
	.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16,
	.FirstBit = SPI_FIRSTBIT_MSB,
	.TIMode = SPI_TIMODE_DISABLE,
	.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
	.CRCPolynomial = 10,
};

static spi_task_t spi_task_ = {
	.config = &spi_config_,
	.ncs_gpio = MAG_ENC_nCS_PIN,
	.on_complete = enc_spi_cplt_handler,
	.on_complete_ctx = (void *)&enc_spi_,
	.next = NULL
};
static void enc_spi_start(void);

void enc_hw_intf_init(init_pos_callback cb, void *ctx) {
#if CONFIG_ENCODER_ABI
	encoder_abi_timer_init(CONFIG_MAG_ENCOCDER_MAX_RES);
#endif
	enc_spi_.cb = cb;
	enc_spi_.ctx = ctx;
	enc_spi_.spi_abs_count = 0;
	gpio_write(MAG_ENC_nCS_PIN, true);
	gpio_init(MAG_ENC_nCS_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
	enc_spi_.spi_abs_dma_tx_[0] = 0xFFFF;
	enc_spi_.spi_abs_count = 0;
	enc_spi_.spi_abi_count = 0;
	enc_spi_.spi_trans_cnt = 0;
	enc_spi_.spi_abs_dma_tx_[0] = 0x3FFF;
	enc_spi_start();
}

static void enc_spi_start(void) {
	if (!spi_acquire_task(&spi_task_)) {
		return;
	}
	spi_task_.next = NULL;
	spi_task_.tx_buf = (u8 *)enc_spi_.spi_abs_dma_tx_;
	spi_task_.rx_buf = (u8 *)enc_spi_.spi_abs_dma_rx_;
	spi_task_.length = 1;

	spi_transfer_task(&spi_task_);
}


static void enc_spi_cplt_handler(void *ctx, bool success) {
	enc_spi_t *ll = (enc_spi_t *)ctx;
	spi_release_task(&spi_task_);
	if (success) {
		u16 abs_count = ll->spi_abs_dma_rx_[0] & (CONFIG_MAG_ENCOCODER_SPI_RES - 1);
		float duty = (float)abs_count / CONFIG_MAG_ENCOCODER_SPI_RES;
		float duty_cnt = pulse_cnt_from_duty(duty);
		ll->spi_abi_count = duty_cnt;
		ll->spi_abs_count = duty_cnt;
		if (ll->cb && (ll->spi_trans_cnt < 20)) {
			ll->cb(ll->ctx,ll->spi_abs_count);
		}
		ll->spi_trans_cnt++;
	}else {
		ll->spi_trans_errors++;
	}
	enc_spi_start();
}

void enc_hw_intf_log(void) {
	sys_debug("enc ll: start %s\n", enc_spi_.b_spi_start_error?"error":"OK");
	sys_debug("enc ll: spi trans err %d, trans %d\n", enc_spi_.spi_trans_errors, enc_spi_.spi_trans_cnt);
	sys_debug("enc ll: spi abs count %d(%f)\n", (int)enc_spi_.spi_abs_count, enc_spi_.spi_abi_count);
}

#endif

